#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据完整性检查脚本
检查根目录、目录结构和虚拟存储表的数据完整性
提供详细的统计信息
"""

import os
import sys
import logging
from datetime import datetime
from collections import defaultdict
from sqlalchemy import text, func

# 添加项目根目录到路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

from src.common.database import get_session, init_global_session
from src.models.file import VirtualFile
from src.models.storage import VirtualStorage
from src.models.base import ROOT_DIRECTORY_ID
from src.utils.config import get_database_url

class DataIntegrityChecker:
    """数据完整性检查器"""
    
    def __init__(self):
        self.issues = []
        
    def check_root_directory(self):
        """检查根目录"""
        print("🔍 检查根目录...")
        
        with get_session() as session:
            # 检查根目录是否存在
            root = session.query(VirtualFile).filter_by(id=ROOT_DIRECTORY_ID).first()
            
            if not root:
                self.issues.append("❌ 根目录不存在（ID=1）")
                print("❌ 根目录不存在（ID=1）")
                return False
            
            # 检查根目录属性
            if root.name != '':
                self.issues.append(f"❌ 根目录名称错误: '{root.name}' (应为空字符串)")
                print(f"❌ 根目录名称错误: '{root.name}' (应为空字符串)")
            
            if root.parent_id is not None:
                self.issues.append(f"❌ 根目录parent_id错误: {root.parent_id} (应为None)")
                print(f"❌ 根目录parent_id错误: {root.parent_id} (应为None)")
            
            if not root.is_folder:
                self.issues.append("❌ 根目录不是文件夹")
                print("❌ 根目录不是文件夹")
            
            if len(self.issues) == 0:
                print(f"✅ 根目录正常: ID={root.id}, name='{root.name}', is_folder={root.is_folder}")
                return True
            else:
                return False
    
    def check_directory_structure(self):
        """检查目录结构完整性"""
        print("\n📁 检查目录结构...")
        
        with get_session() as session:
            # 检查孤儿文件（parent_id指向不存在的记录）
            orphan_query = text("""
                SELECT vf1.id, vf1.name, vf1.parent_id, vf1.is_folder
                FROM virtual_files vf1 
                WHERE vf1.parent_id IS NOT NULL 
                AND NOT EXISTS (
                    SELECT 1 FROM virtual_files vf2 
                    WHERE vf2.id = vf1.parent_id
                )
            """)
            
            orphans = session.execute(orphan_query).fetchall()
            
            if orphans:
                print(f"⚠️ 发现 {len(orphans)} 个孤儿文件")
                for orphan in orphans[:10]:  # 只显示前10个
                    file_type = "文件夹" if orphan.is_folder else "文件"
                    print(f"   - ID:{orphan.id}, 名称:'{orphan.name}', 类型:{file_type}, 父ID:{orphan.parent_id}")
                if len(orphans) > 10:
                    print(f"   ... 还有 {len(orphans) - 10} 个")
                self.issues.append(f"发现 {len(orphans)} 个孤儿文件")
            else:
                print("✅ 未发现孤儿文件")
            
            # 统计目录结构
            total_files = session.query(VirtualFile).count()
            total_folders = session.query(VirtualFile).filter_by(is_folder=True).count()
            total_regular_files = total_files - total_folders
            
            print(f"📊 目录结构统计:")
            print(f"   - 总节点数: {total_files}")
            print(f"   - 文件夹数: {total_folders}")
            print(f"   - 文件数: {total_regular_files}")
            
            # 检查根目录下的直接子目录
            root_children = session.query(VirtualFile).filter_by(parent_id=ROOT_DIRECTORY_ID).all()
            print(f"   - 根目录直接子项: {len(root_children)}")
            for child in root_children:
                file_type = "📁" if child.is_folder else "📄"
                print(f"     {file_type} {child.name}")
    
    def analyze_storage_by_size(self):
        """按文件大小分析虚拟存储"""
        print("\n📊 按文件大小分析虚拟存储...")
        
        with get_session() as session:
            # 获取文件大小范围
            size_stats = session.query(
                func.min(VirtualStorage.file_size_bytes).label('min_size'),
                func.max(VirtualStorage.file_size_bytes).label('max_size'),
                func.count(VirtualStorage.id).label('total_count')
            ).first()
            
            if size_stats.total_count == 0:
                print("📭 虚拟存储表为空")
                return
            
            print(f"📈 文件大小统计:")
            print(f"   - 总文件数: {size_stats.total_count}")
            print(f"   - 最小文件: {self._format_size(size_stats.min_size)}")
            print(f"   - 最大文件: {self._format_size(size_stats.max_size)}")
            
            # 定义大小范围（字节）
            size_ranges = [
                (0, 1024**3, "< 1GB"),
                (1024**3, 2*1024**3, "1GB ~ 2GB"),
                (2*1024**3, 3*1024**3, "2GB ~ 3GB"),
                (3*1024**3, 5*1024**3, "3GB ~ 5GB"),
                (5*1024**3, 10*1024**3, "5GB ~ 10GB"),
                (10*1024**3, 15*1024**3, "10GB ~ 15GB"),
                (15*1024**3, 20*1024**3, "15GB ~ 20GB"),
                (20*1024**3, 30*1024**3, "20GB ~ 30GB"),
                (30*1024**3, 50*1024**3, "30GB ~ 50GB"),
                (50*1024**3, 70*1024**3, "50GB ~ 70GB"),
                (70*1024**3, 100*1024**3, "70GB ~ 100GB"),
                (100*1024**3, float('inf'), "> 100GB")
            ]
            
            print(f"\n📋 文件大小分布:")
            total_size = 0
            for min_size, max_size, label in size_ranges:
                if max_size == float('inf'):
                    count = session.query(VirtualStorage).filter(
                        VirtualStorage.file_size_bytes >= min_size
                    ).count()
                    size_sum = session.query(func.sum(VirtualStorage.file_size_bytes)).filter(
                        VirtualStorage.file_size_bytes >= min_size
                    ).scalar() or 0
                else:
                    count = session.query(VirtualStorage).filter(
                        VirtualStorage.file_size_bytes >= min_size,
                        VirtualStorage.file_size_bytes < max_size
                    ).count()
                    size_sum = session.query(func.sum(VirtualStorage.file_size_bytes)).filter(
                        VirtualStorage.file_size_bytes >= min_size,
                        VirtualStorage.file_size_bytes < max_size
                    ).scalar() or 0
                
                if count > 0:
                    print(f"   {label:>15}: {count:>6} 个文件, 总大小: {self._format_size(size_sum)}")
                    total_size += size_sum
            
            print(f"\n💾 总存储空间: {self._format_size(total_size)}")
    
    def analyze_storage_by_type(self):
        """按文件类型分析虚拟存储"""
        print("\n📊 按文件类型分析虚拟存储...")
        
        with get_session() as session:
            # 按文件扩展名统计
            type_stats = session.query(
                VirtualStorage.file_extension,
                func.count(VirtualStorage.id).label('count'),
                func.sum(VirtualStorage.file_size_bytes).label('total_size'),
                func.min(VirtualStorage.file_size_bytes).label('min_size'),
                func.max(VirtualStorage.file_size_bytes).label('max_size')
            ).group_by(VirtualStorage.file_extension).order_by(func.count(VirtualStorage.id).desc()).all()
            
            if not type_stats:
                print("📭 虚拟存储表为空")
                return
            
            print(f"📋 文件类型分布 (按数量排序):")
            print(f"{'类型':>10} {'数量':>8} {'总大小':>12} {'最小':>10} {'最大':>10}")
            print("-" * 60)
            
            # 定义常见文件类型分组
            video_exts = {'mp4', 'avi', 'mkv', 'mov', 'wmv', 'flv', 'webm', 'm4v'}
            audio_exts = {'mp3', 'wav', 'flac', 'aac', 'm4a', 'ogg', 'wma'}
            image_exts = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'tiff'}
            document_exts = {'pdf', 'doc', 'docx', 'txt', 'rtf', 'odt'}
            archive_exts = {'zip', 'rar', '7z', 'tar', 'gz', 'bz2'}
            
            type_groups = defaultdict(lambda: {'count': 0, 'size': 0})
            
            for stat in type_stats:
                ext = stat.file_extension or 'unknown'
                count = stat.count
                total_size = stat.total_size or 0
                min_size = stat.min_size or 0
                max_size = stat.max_size or 0
                
                print(f"{ext:>10} {count:>8} {self._format_size(total_size):>12} {self._format_size(min_size):>10} {self._format_size(max_size):>10}")
                
                # 分组统计
                if ext.lower() in video_exts:
                    type_groups['视频']['count'] += count
                    type_groups['视频']['size'] += total_size
                elif ext.lower() in audio_exts:
                    type_groups['音频']['count'] += count
                    type_groups['音频']['size'] += total_size
                elif ext.lower() in image_exts:
                    type_groups['图片']['count'] += count
                    type_groups['图片']['size'] += total_size
                elif ext.lower() in document_exts:
                    type_groups['文档']['count'] += count
                    type_groups['文档']['size'] += total_size
                elif ext.lower() in archive_exts:
                    type_groups['压缩包']['count'] += count
                    type_groups['压缩包']['size'] += total_size
                else:
                    type_groups['其他']['count'] += count
                    type_groups['其他']['size'] += total_size
            
            print(f"\n📊 文件类型分组统计:")
            for group_name, stats in sorted(type_groups.items(), key=lambda x: x[1]['count'], reverse=True):
                if stats['count'] > 0:
                    print(f"   {group_name:>6}: {stats['count']:>6} 个文件, 总大小: {self._format_size(stats['size'])}")
    
    def _format_size(self, size_bytes):
        """格式化文件大小"""
        if size_bytes is None:
            return "0B"
        
        if size_bytes == 0:
            return "0B"
        
        units = ['B', 'KB', 'MB', 'GB', 'TB']
        unit_index = 0
        size = float(size_bytes)
        
        while size >= 1024 and unit_index < len(units) - 1:
            size /= 1024
            unit_index += 1
        
        if unit_index == 0:
            return f"{int(size)}{units[unit_index]}"
        else:
            return f"{size:.1f}{units[unit_index]}"
    
    def run_full_check(self):
        """运行完整检查"""
        print("="*80)
        print("🔍 WebDAV数据完整性检查")
        print("="*80)
        
        # 1. 检查根目录
        root_ok = self.check_root_directory()
        
        # 2. 检查目录结构
        self.check_directory_structure()
        
        # 3. 分析虚拟存储（按大小）
        self.analyze_storage_by_size()
        
        # 4. 分析虚拟存储（按类型）
        self.analyze_storage_by_type()
        
        # 总结
        print("\n" + "="*80)
        print("📋 检查总结")
        print("="*80)
        
        if self.issues:
            print("❌ 发现以下问题:")
            for issue in self.issues:
                print(f"   - {issue}")
            print(f"\n建议运行数据初始化脚本修复问题:")
            print(f"   python extensions/data_initializer.py --full")
        else:
            print("✅ 数据完整性检查通过，未发现问题")
        
        print("="*80)
        
        return len(self.issues) == 0

def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description='WebDAV数据完整性检查工具')
    parser.add_argument('--root-only', action='store_true', help='仅检查根目录')
    parser.add_argument('--structure-only', action='store_true', help='仅检查目录结构')
    parser.add_argument('--storage-size', action='store_true', help='仅分析存储大小')
    parser.add_argument('--storage-type', action='store_true', help='仅分析存储类型')
    
    args = parser.parse_args()
    
    checker = DataIntegrityChecker()
    
    if args.root_only:
        checker.check_root_directory()
    elif args.structure_only:
        checker.check_directory_structure()
    elif args.storage_size:
        checker.analyze_storage_by_size()
    elif args.storage_type:
        checker.analyze_storage_by_type()
    else:
        # 默认执行完整检查
        checker.run_full_check()

if __name__ == '__main__':
    main()
